home *** CD-ROM | disk | FTP | other *** search
/ The Very Best of Atari Inside / The Very Best of Atari Inside 1.iso / mint / mint99s / dosfile.c < prev    next >
C/C++ Source or Header  |  1993-01-13  |  25KB  |  1,132 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith.
  3. Copyright 1992 Atari Corporation.
  4. All rights reserved.
  5. */
  6.  
  7. /* DOS file handling routines */
  8.  
  9. #include "mint.h"
  10.  
  11. extern char temp1[];    /* see filesys.c */
  12.  
  13. static long do_dup P_((int,int));
  14. static void unselectme P_((PROC *));
  15.  
  16. /*
  17.  * first, some utility routines
  18.  */
  19.  
  20. FILEPTR *
  21. do_open(name, rwmode, attr, x)
  22.     const char *name;    /* file name */
  23.     int rwmode;    /* file access mode */
  24.     int attr;    /* TOS attributes for created files (if applicable) */
  25.     XATTR *x;    /* filled in with attributes of opened file */
  26. {
  27.     struct tty *tty;
  28.     fcookie dir, fc;
  29.     long devsp;
  30.     FILEPTR *f;
  31.     DEVDRV *dev;
  32.     long r;
  33.     XATTR xattr;
  34.     unsigned perm;
  35.     int creating;
  36.     extern FILESYS proc_filesys;
  37.  
  38. /* for special BIOS "fake" devices */
  39.     extern DEVDRV fakedev;
  40.  
  41.     TRACE(("do_open(%s)", name));
  42.  
  43. /*
  44.  * first step: get a cookie for the directory
  45.  */
  46.  
  47.     r = path2cookie(name, temp1, &dir);
  48.     if (r) {
  49.         mint_errno = (int)r;
  50.         DEBUG(("do_open(%s): error %ld", name, r));
  51.         return NULL;
  52.     }
  53.  
  54. /*
  55.  * second step: try to locate the file itself
  56.  */
  57.     r = relpath2cookie(&dir, temp1, follow_links, &fc, 0);
  58.  
  59. /*
  60.  * file found: this is an error if (O_CREAT|O_EXCL) are set
  61.  */
  62.  
  63.     if ( (r == 0) && ( (rwmode & (O_CREAT|O_EXCL)) == (O_CREAT|O_EXCL) ) ) {
  64.         DEBUG(("do_open(%s): file already exists",name));
  65.         mint_errno = EACCDN;
  66.         release_cookie(&fc);
  67.         release_cookie(&dir);
  68.         return NULL;
  69.     }
  70. /*
  71.  * file not found: maybe we should create it
  72.  * note that if r != 0, the fc cookie is invalid (so we don't need to
  73.  * release it)
  74.  */
  75.     if (r == EFILNF && (rwmode & O_CREAT)) {
  76.     /* check first for write permission in the directory */
  77.         r = (*dir.fs->getxattr)(&dir, &xattr);
  78.         if (r == 0) {
  79.             if (denyaccess(&xattr, S_IWOTH))
  80.                 r = EACCDN;
  81.         }
  82.         if (r) {
  83.             DEBUG(("do_open(%s): couldn't get "
  84.                   "write permission on directory",name));
  85.             mint_errno = (int)r;
  86.             release_cookie(&dir);
  87.             return NULL;
  88.         }
  89.         r = (*dir.fs->creat)(&dir, temp1,
  90.             (S_IFREG|DEFAULT_MODE) & (~curproc->umask), attr, &fc);
  91.         if (r) {
  92.             DEBUG(("do_open(%s): error %ld while creating file",
  93.                 name, r));
  94.             mint_errno = (int)r;
  95.             release_cookie(&dir);
  96.             return NULL;
  97.         }
  98.         creating = 1;
  99.     } else if (r) {
  100.         DEBUG(("do_open(%s): error %ld while searching for file",
  101.             name, r));
  102.         mint_errno = (int)r;
  103.         release_cookie(&dir);
  104.         return NULL;
  105.     } else {
  106.         creating = 0;
  107.     }
  108.  
  109. /*
  110.  * check now for permission to actually access the file
  111.  */
  112.     r = (*fc.fs->getxattr)(&fc, &xattr);
  113.     if (r) {
  114.         DEBUG(("do_open(%s): couldn't get file attributes",name));
  115.         mint_errno = (int)r;
  116.         release_cookie(&dir);
  117.         release_cookie(&fc);
  118.         return NULL;
  119.     }
  120. /*
  121.  * we don't do directories
  122.  */
  123.     if ( (xattr.mode & S_IFMT) == S_IFDIR ) {
  124.         DEBUG(("do_open(%s): file is a directory",name));
  125.         release_cookie(&dir);
  126.         release_cookie(&fc);
  127.         mint_errno = EFILNF;
  128.         return NULL;
  129.     }
  130.  
  131.     switch (rwmode & O_RWMODE) {
  132.     case O_WRONLY:
  133.         perm = S_IWOTH;
  134.         break;
  135.     case O_RDWR:
  136.         perm = S_IROTH|S_IWOTH;
  137.         break;
  138.     case O_EXEC:
  139.         perm = (fc.fs->fsflags & FS_NOXBIT) ? S_IROTH : S_IXOTH;
  140.         break;
  141.     case O_RDONLY:
  142.         perm = S_IROTH;
  143.         break;
  144.     default:
  145.         perm = 0;
  146.         ALERT("do_open: bad file access mode: %x", rwmode);
  147.     }
  148.     if (!creating && denyaccess(&xattr, perm)) {
  149.         DEBUG(("do_open(%s): access to file denied",name));
  150.         release_cookie(&dir);
  151.         release_cookie(&fc);
  152.         mint_errno = EACCDN;
  153.         return NULL;
  154.     }
  155.  
  156. /*
  157.  * an extra check for write access -- even the superuser shouldn't
  158.  * write to files with the FA_RDONLY attribute bit set (unless,
  159.  * we just created the file, or unless the file is on the proc
  160.  * file system and hence FA_RDONLY has a different meaning)
  161.  */
  162.     if ( !creating && (xattr.attr & FA_RDONLY) && fc.fs != &proc_filesys) {
  163.         if ( (rwmode & O_RWMODE) == O_RDWR ||
  164.              (rwmode & O_RWMODE) == O_WRONLY ) {
  165.             DEBUG(("do_open(%s): can't write a read-only file",
  166.                 name));
  167.             release_cookie(&dir);
  168.             release_cookie(&fc);
  169.             mint_errno = EACCDN;
  170.             return NULL;
  171.         }
  172.     }
  173.  
  174. /*
  175.  * if writing to a setuid or setgid file, clear those bits
  176.  */
  177.     if ( (perm & S_IWOTH) && (xattr.mode & (S_ISUID|S_ISGID)) ) {
  178.         xattr.mode &= ~(S_ISUID|S_ISGID);
  179.         (*fc.fs->chmode)(&fc, (xattr.mode & ~S_IFMT));
  180.     }
  181. /*
  182.  * If the caller asked for the attributes of the opened file, copy them over.
  183.  */
  184.     if (x) *x = xattr;
  185.  
  186. /*
  187.  * So far, so good. Let's get the device driver now, and try to
  188.  * actually open the file.
  189.  */
  190.     dev = (*fc.fs->getdev)(&fc, &devsp);
  191.     if (!dev) {
  192.         mint_errno = (int)devsp;
  193.         DEBUG(("do_open(%s): device driver not found",name));
  194.         release_cookie(&dir);
  195.         release_cookie(&fc);
  196.         return NULL;
  197.     }
  198.  
  199.     if (dev == &fakedev) {        /* fake BIOS devices */
  200.         f = curproc->handle[devsp];
  201.         if (!f) {
  202.             mint_errno = EIHNDL;
  203.             return 0;
  204.         }
  205.         f->links++;
  206.         release_cookie(&dir);
  207.         release_cookie(&fc);
  208.         return f;
  209.     }
  210.     if (0 == (f = new_fileptr())) {
  211.         release_cookie(&dir);
  212.         release_cookie(&fc);
  213.         mint_errno = ENSMEM;
  214.         return NULL;
  215.     }
  216.     f->links = 1;
  217.     f->flags = rwmode;
  218.     f->pos = 0;
  219.     f->devinfo = devsp;
  220.     f->fc = fc;
  221.     f->dev = dev;
  222.     release_cookie(&dir);
  223.  
  224.     r = (*dev->open)(f);
  225.     if (r < 0) {
  226.         DEBUG(("do_open(%s): device open failed with error %ld",
  227.             name, r));
  228.         mint_errno = (int)r;
  229.         f->links = 0;
  230.         release_cookie(&fc);
  231.         dispose_fileptr(f);
  232.         return NULL;
  233.     }
  234.  
  235. /* special code for opening a tty */
  236.     if (is_terminal(f)) {
  237.         extern struct tty default_tty;    /* in tty.c */
  238.  
  239.         tty = (struct tty *)f->devinfo;
  240.         if (tty->use_cnt == 0) {     /* first open for this device? */
  241.             *tty = default_tty;
  242.         }
  243.         tty->use_cnt++;
  244.     }
  245.     return f;
  246. }
  247.  
  248. /*
  249.  * helper function for do_close: this closes the indicated file pointer which
  250.  * is assumed to be associated with process p. The extra parameter is necessary
  251.  * because f_midipipe mucks with file pointers of other processes, so
  252.  * sometimes p != curproc.
  253.  *
  254.  * Note that the function changedrv() in filesys.c can call this routine.
  255.  * in that case, f->dev will be 0 to represent an invalid device, and
  256.  * we cannot call the device close routine.
  257.  */
  258.  
  259. long
  260. do_pclose(p, f)
  261.     PROC *p;
  262.     FILEPTR *f;
  263. {
  264.     long r = 0;
  265.  
  266.     if (!f) return EIHNDL;
  267.  
  268. /* if this file is "select'd" by this process, unselect it
  269.  * (this is just in case we were killed by a signal)
  270.  */
  271.  
  272. /* BUG? Feature? If media change is detected while we're doing the select,
  273.  * we'll never unselect (since f->dev is set to NULL by changedrv())
  274.  */
  275.     if (f->dev) {
  276.         (*f->dev->unselect)(f, (long)p, O_RDONLY);
  277.         (*f->dev->unselect)(f, (long)p, O_WRONLY);
  278.     }
  279.  
  280.     f->links--;
  281.  
  282. /* TTY manipulation must be done *before* calling the device close routine,
  283.  * since afterwards the TTY structure may no longer exist
  284.  */
  285.     if (is_terminal(f) && f->links <= 0) {
  286.         struct tty *tty = (struct tty *)f->devinfo;
  287.         tty->use_cnt--;
  288.         if (tty->use_cnt <= 0)
  289.             tty->pgrp = 0;
  290.         if (tty->use_cnt <= 0 && tty->xkey) {
  291.             kfree(tty->xkey);
  292.             tty->xkey = 0;
  293.         }
  294.     }
  295.  
  296.     if (f->dev) {
  297.         r = (*f->dev->close)(f, p->pid);
  298.         if (r) {
  299.             DEBUG(("close: device close failed"));
  300.         }
  301.     }
  302.     if (f->links <= 0) {
  303.         release_cookie(&f->fc);
  304.         dispose_fileptr(f);
  305.     }
  306.     return  r;
  307. }
  308.  
  309. long
  310. do_close(f)
  311.     FILEPTR *f;
  312. {
  313.     return do_pclose(curproc, f);
  314. }
  315.  
  316. long ARGS_ON_STACK
  317. f_open(name, mode)
  318.     const char *name;
  319.     int mode;
  320. {
  321.     int i;
  322.     FILEPTR *f;
  323.     PROC *proc;
  324.  
  325.     TRACE(("Fopen(%s, %x)", name, mode));
  326. #if O_GLOBAL
  327.     if (mode & O_GLOBAL) {
  328.         /* oh, boy! user wants us to open a global handle! */
  329.         proc = rootproc;
  330.     }
  331.     else
  332. #endif
  333.         proc = curproc;
  334.  
  335.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  336.         if (!proc->handle[i])
  337.             goto found_for_open;
  338.     }
  339.     DEBUG(("Fopen(%s): process out of handles",name));
  340.     return ENHNDL;        /* no more handles */
  341.  
  342. found_for_open:
  343.     mode &= O_USER;        /* make sure the mode is legal */
  344.  
  345. /* note: file mode 3 is reserved for the kernel; for users, transmogrify it
  346.  * into O_RDWR (mode 2)
  347.  */
  348.     if ( (mode & O_RWMODE) == O_EXEC ) {
  349.         mode = (mode & ~O_RWMODE) | O_RDWR;
  350.     }
  351.  
  352.     f = do_open(name, mode, 0, (XATTR *)0);
  353.  
  354.  
  355.     if (!f) {
  356.         return mint_errno;
  357.     }
  358.     proc->handle[i] = f;
  359. /* default is to close non-standard files on exec */
  360.     proc->fdflags[i] = FD_CLOEXEC;
  361.  
  362. #if O_GLOBAL
  363.     if (proc != curproc) {
  364.         /* we just opened a global handle */
  365.         i += 100;
  366.     }
  367. #endif
  368.  
  369.     TRACE(("Fopen: returning %d", i));
  370.     return i;
  371. }
  372.  
  373. long ARGS_ON_STACK
  374. f_create(name, attrib)
  375.     const char *name;
  376.     int attrib;
  377. {
  378.     fcookie dir;
  379.     int i;
  380.     FILEPTR *f;
  381.     long r;
  382.     PROC *proc;
  383.     int offset = 0;
  384.  
  385.     TRACE(("Fcreate(%s, %x)", name, attrib));
  386. #if O_GLOBAL
  387.     if (attrib & O_GLOBAL) {
  388.         proc = rootproc;
  389.         offset = 100;
  390.         attrib &= ~O_GLOBAL;
  391.     }
  392.     else
  393. #endif
  394.         proc = curproc;
  395.  
  396.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  397.         if (!proc->handle[i])
  398.             goto found_for_create;
  399.     }
  400.     DEBUG(("Fcreate(%s): process out of handles",name));
  401.     return ENHNDL;        /* no more handles */
  402.  
  403. found_for_create:
  404.     if (attrib == FA_LABEL) {
  405.         r = path2cookie(name, temp1, &dir);
  406.         if (r) return r;
  407.         r = (*dir.fs->writelabel)(&dir, temp1);
  408.         release_cookie(&dir);
  409.         if (r) return r;
  410. /*
  411.  * just in case the caller tries to do something with this handle,
  412.  * make it point to u:\dev\null
  413.  */
  414.         f = do_open("u:\\dev\\null", O_RDWR|O_CREAT|O_TRUNC, 0,
  415.                  (XATTR *)0);
  416.         proc->handle[i] = f;
  417.         return i+offset;
  418.     }
  419.     if (attrib & (FA_LABEL|FA_DIR)) {
  420.         DEBUG(("Fcreate(%s,%x): illegal attributes",name,attrib));
  421.         return EACCDN;
  422.     }
  423.  
  424.     f = do_open(name, O_RDWR|O_CREAT|O_TRUNC, attrib, (XATTR *)0);
  425.  
  426.     if (!f) {
  427.         DEBUG(("Fcreate(%s) failed, error %d", name, mint_errno));
  428.         return mint_errno;
  429.     }
  430.     proc->handle[i] = f;
  431.     i += offset;
  432.     TRACE(("Fcreate: returning %d", i));
  433.     return i;
  434. }
  435.  
  436. long ARGS_ON_STACK
  437. f_close(fh)
  438.     int fh;
  439. {
  440.     FILEPTR *f;
  441.     long r;
  442.     PROC *proc;
  443.  
  444.     TRACE(("Fclose: %d", fh));
  445. #if O_GLOBAL
  446.     if (fh >= 100) {
  447.         fh -= 100;
  448.         proc = rootproc;
  449.     }
  450.     else
  451. #endif
  452.         proc = curproc;
  453.  
  454.     if (fh < 0 || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  455.         return EIHNDL;
  456.     }
  457.     r = do_pclose(proc, f);
  458.  
  459. /* standard handles should be restored to default values */
  460. /* do this for TOS domain only! */
  461.     if (proc->domain == DOM_TOS) {
  462.         if (fh == 0 || fh == 1)
  463.             f = proc->handle[-1];
  464.         else if (fh == 2 || fh == 3)
  465.             f = proc->handle[-fh];
  466.         else
  467.             f = 0;
  468.     } else
  469.         f = 0;
  470.  
  471.     if (f) f->links++;
  472.     proc->handle[fh] = f;
  473.     return r;
  474. }
  475.  
  476. long ARGS_ON_STACK
  477. f_read(fh, count, buf)
  478.     int fh;
  479.     long count;
  480.     char *buf;
  481. {
  482.     FILEPTR *f;
  483.  
  484.     PROC *proc;
  485.  
  486. #if O_GLOBAL
  487.     if (fh >= 100) {
  488.         fh -= 100;
  489.         proc = rootproc;
  490.     }
  491.     else
  492. #endif
  493.         proc = curproc;
  494.  
  495.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  496.         DEBUG(("Fread: invalid handle: %d", fh));
  497.         return EIHNDL;
  498.     }
  499.     if ( (f->flags & O_RWMODE) == O_WRONLY ) {
  500.         DEBUG(("Fread: read on a write-only handle"));
  501.         return EACCDN;
  502.     }
  503.     if (is_terminal(f))
  504.         return tty_read(f, buf, count);
  505.  
  506.     TRACELOW(("Fread: %ld bytes from handle %d to %lx", count, fh, buf));
  507.     return (*f->dev->read)(f, buf, count);
  508. }
  509.  
  510. long ARGS_ON_STACK
  511. f_write(fh, count, buf)
  512.     int fh;
  513.     long count;
  514.     const char *buf;
  515. {
  516.     FILEPTR *f;
  517.     PROC *proc;
  518.     long r;
  519.  
  520. #if O_GLOBAL
  521.     if (fh >= 100) {
  522.         fh -= 100;
  523.         proc = rootproc;
  524.     }
  525.     else
  526. #endif
  527.         proc = curproc;
  528.  
  529.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  530.         DEBUG(("Fwrite: bad handle: %d", fh));
  531.         return EIHNDL;
  532.     }
  533.     if ( (f->flags & O_RWMODE) == O_RDONLY ) {
  534.         DEBUG(("Fwrite: write on a read-only handle"));
  535.         return EACCDN;
  536.     }
  537.     if (is_terminal(f))
  538.         return tty_write(f, buf, count);
  539.  
  540.     /* it would be faster to do this in the device driver, but this
  541.      * way the drivers are easier to write
  542.      */
  543.     if (f->flags & O_APPEND)
  544.         r = (*f->dev->lseek)(f, 0L, SEEK_END);
  545.     else
  546.         r = 0;
  547.     if (r >= 0) {
  548.         TRACELOW(("Fwrite: %ld bytes to handle %d", count, fh));
  549.         r = (*f->dev->write)(f, buf, count);
  550.     }
  551.     if (r < 0) {
  552.         DEBUG(("Fwrite: error %ld", r));
  553.     }
  554.     return r;
  555. }
  556.  
  557. long ARGS_ON_STACK
  558. f_seek(place, fh, how)
  559.     long place;
  560.     int fh;
  561.     int how;
  562. {
  563.     FILEPTR *f;
  564.     PROC *proc;
  565.  
  566.     TRACE(("Fseek(%ld, %d) on handle %d", place, how, fh));
  567. #if O_GLOBAL
  568.     if (fh >= 100) {
  569.         fh -= 100;
  570.         proc = rootproc;
  571.     }
  572.     else
  573. #endif
  574.         proc = curproc;
  575.  
  576.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  577.         DEBUG(("Fseek: bad handle: %d", fh));
  578.         return EIHNDL;
  579.     }
  580.     if (is_terminal(f)) {
  581.         return 0;
  582.     }
  583.     return (*f->dev->lseek)(f, place, how);
  584. }
  585.  
  586. /* duplicate file pointer fh; returns a new file pointer >= min, if
  587.    one exists, or ENHNDL if not. called by f_dup and f_cntl
  588.  */
  589.  
  590. static long do_dup(fh, min)
  591.     int fh, min;
  592. {
  593.     FILEPTR *f;
  594.     int i;
  595.     PROC *proc;
  596.  
  597.     for (i = min; i < MAX_OPEN; i++) {
  598.         if (!curproc->handle[i])
  599.             goto found;
  600.     }
  601.     return ENHNDL;        /* no more handles */
  602. found:
  603. #if O_GLOBAL
  604.     if (fh >= 100) {
  605.         fh -= 100;
  606.         proc = rootproc;
  607.     } else
  608. #endif
  609.         proc = curproc;
  610.  
  611.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh]))
  612.         return EIHNDL;
  613.  
  614.     curproc->handle[i] = f;
  615.  
  616. /* set default file descriptor flags */
  617.     if (i >= 0) {
  618.         if (i >= MIN_OPEN)
  619.             curproc->fdflags[i] = FD_CLOEXEC;
  620.         else
  621.             curproc->fdflags[i] = 0;
  622.     }
  623.     f->links++;
  624.     return i;
  625. }
  626.  
  627. long ARGS_ON_STACK
  628. f_dup(fh)
  629.     int fh;
  630. {
  631.     long r;
  632.     r = do_dup(fh, MIN_OPEN);
  633.     TRACE(("Fdup(%d) -> %ld", fh, r));
  634.     return r;
  635. }
  636.  
  637. long ARGS_ON_STACK
  638. f_force(newh, oldh)
  639.     int newh;
  640.     int oldh;
  641. {
  642.     FILEPTR *f;
  643.     PROC *proc;
  644.  
  645.     TRACE(("Fforce(%d, %d)", newh, oldh));
  646.  
  647. #if O_GLOBAL
  648.     if (oldh >= 100) {
  649.         oldh -= 100;
  650.         proc = rootproc;
  651.     } else
  652. #endif
  653.         proc = curproc;
  654.  
  655.     if (oldh < MIN_HANDLE || oldh >= MAX_OPEN ||
  656.         0 == (f = proc->handle[oldh])) {
  657.         DEBUG(("Fforce: old handle invalid"));
  658.         return EIHNDL;
  659.     }
  660.  
  661.     if (newh < MIN_HANDLE || newh >= MAX_OPEN) {
  662.         DEBUG(("Fforce: new handle out of range"));
  663.         return EIHNDL;
  664.     }
  665.  
  666.     (void)do_close(curproc->handle[newh]);
  667.     curproc->handle[newh] = f;
  668.     f->links++;
  669. /*
  670.  * special: for a tty, if this is becoming a control terminal and the
  671.  * tty doesn't have a pgrp yet, make it have the pgrp of the process
  672.  * doing the Fforce
  673.  */
  674.     if (is_terminal(f) && newh == -1) {
  675.         struct tty *tty = (struct tty *)f->devinfo;
  676.  
  677.         if (!tty->pgrp)
  678.             tty->pgrp = curproc->pgrp;
  679.     }
  680.     return newh;
  681. }
  682.  
  683. long ARGS_ON_STACK
  684. f_datime(timeptr, fh, rwflag)
  685.     short *timeptr;
  686.     int fh;
  687.     int rwflag;
  688. {
  689.     FILEPTR *f;
  690.     PROC *proc;
  691.  
  692.     TRACE(("Fdatime(%d)", fh));
  693. #if O_GLOBAL
  694.     if (fh >= 100) {
  695.         fh -= 100;
  696.         proc = rootproc;
  697.     }
  698.     else
  699. #endif
  700.         proc = curproc;
  701.  
  702.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  703.         DEBUG(("Fdatime: invalid handle"));
  704.         return EIHNDL;
  705.     }
  706.  
  707. /* some programs use Fdatime to test for TTY devices */
  708.     if (is_terminal(f))
  709.         return EACCDN;
  710.  
  711.     return (*f->dev->datime)(f, timeptr, rwflag);
  712. }
  713.  
  714. long ARGS_ON_STACK
  715. f_lock(fh, mode, start, length)
  716.     int fh, mode;
  717.     long start, length;
  718. {
  719.     FILEPTR *f;
  720.     struct flock lock;
  721.     PROC *proc;
  722.  
  723. #if O_GLOBAL
  724.     if (fh >= 100) {
  725.         fh -= 100;
  726.         proc = rootproc;
  727.     }
  728.     else
  729. #endif
  730.         proc = curproc;
  731.  
  732.     if (fh < MIN_HANDLE || fh >= MAX_OPEN || 0 == (f = proc->handle[fh])) {
  733.         DEBUG(("Flock: invalid handle"));
  734.         return EIHNDL;
  735.     }
  736.     TRACE(("Flock(%d,%d,%ld,%ld)", fh, mode, start, length));
  737.     lock.l_whence = SEEK_SET;
  738.     lock.l_start = start;
  739.     lock.l_len = length;
  740.  
  741.     if (mode == 0)        /* create a lock */
  742.         lock.l_type = F_WRLCK;
  743.     else if (mode == 1)    /* unlock region */
  744.         lock.l_type = F_UNLCK;
  745.     else
  746.         return EINVFN;
  747.  
  748.     return (*f->dev->ioctl)(f, F_SETLK, &lock);
  749. }
  750.  
  751. /*
  752.  * extensions to GEMDOS:
  753.  */
  754.  
  755. /*
  756.  * Fpipe(int *handles): opens a pipe. if successful, returns 0, and
  757.  * sets handles[0] to a file descriptor for the read end of the pipe
  758.  * and handles[1] to one for the write end.
  759.  */
  760.  
  761. long ARGS_ON_STACK
  762. f_pipe(usrh)
  763.     short *usrh;
  764. {
  765.     FILEPTR *in, *out;
  766.     static int pipeno = 0;
  767.     int i, j;
  768.     char pipename[32]; /* MAGIC: 32 >= strlen "u:\pipe\sys$pipe.000\0" */
  769.  
  770.     TRACE(("Fpipe"));
  771.  
  772. /* BUG: more than 999 open pipes hangs the system */
  773.     do {
  774.         ksprintf(pipename, "u:\\pipe\\sys$pipe.%03d", pipeno);
  775.         pipeno++; if (pipeno > 999) pipeno = 0;
  776.         out = do_open(pipename, O_WRONLY|O_CREAT|O_EXCL, FA_RDONLY|FA_HIDDEN|FA_CHANGED,
  777.                  (XATTR *)0);
  778.             /* read-only attribute means unidirectional fifo */
  779.             /* hidden attribute means check for broken pipes */
  780.             /* changed attribute means act like Unix fifos */
  781.     } while (out == 0 && mint_errno == EACCDN);
  782.  
  783.     if (!out) {
  784.         DEBUG(("Fpipe: error %d", mint_errno));
  785.         return mint_errno;
  786.     }
  787.  
  788.     in = do_open(pipename, O_RDONLY, 0, (XATTR *)0);
  789.     if (!in) {
  790.         DEBUG(("Fpipe: in side of pipe not opened (error %d)",
  791.             mint_errno));
  792.         (void)do_close(out);
  793.         return mint_errno;
  794.     }
  795.  
  796.     for (i = MIN_OPEN; i < MAX_OPEN; i++) {
  797.         if (curproc->handle[i] == 0)
  798.             break;
  799.     }
  800.  
  801.     for (j = i+1; j < MAX_OPEN; j++) {
  802.         if (curproc->handle[j] == 0)
  803.             break;
  804.     }
  805.  
  806.     if (j >= MAX_OPEN) {
  807.         DEBUG(("Fpipe: not enough handles left"));
  808.         (void) do_close(in);
  809.         (void) do_close(out);
  810.         return ENHNDL;
  811.     }
  812.     curproc->handle[i] = in; curproc->handle[j] = out;
  813. /* leave pipes open across Pexec */
  814.     curproc->fdflags[i] = 0;
  815.     curproc->fdflags[j] = 0;
  816.  
  817.     usrh[0] = i;
  818.     usrh[1] = j;
  819.     TRACE(("Fpipe: returning 0: input %d output %d",i,j));
  820.     return 0;
  821. }
  822.  
  823. /*
  824.  * f_cntl: a combination "ioctl" and "fcntl". Some functions are
  825.  * handled here, if they apply to the file descriptors directly
  826.  * (e.g. F_DUPFD) or if they're easily translated into file system
  827.  * functions (e.g. FSTAT). Others are passed on to the device driver
  828.  * via dev->ioctl.
  829.  */
  830.  
  831. long ARGS_ON_STACK
  832. f_cntl(fh, arg, cmd)
  833.     int fh;
  834.     long arg;
  835.     int cmd;
  836. {
  837.     FILEPTR    *f;
  838.     PROC *proc;
  839.     struct flock *fl;
  840.     long r;
  841.  
  842.     TRACE(("Fcntl(%d, cmd=0x%x)", fh, cmd));
  843. #if O_GLOBAL
  844.     if (fh >= 100) {
  845.         fh -= 100;
  846.         proc = rootproc;
  847.     }
  848.     else
  849. #endif
  850.         proc = curproc;
  851.  
  852.     if (fh < MIN_HANDLE || fh >= MAX_OPEN) {
  853.         DEBUG(("Fcntl: bad file handle"));
  854.         return EIHNDL;
  855.     }
  856.  
  857.     if (cmd == F_DUPFD) {
  858. #if O_GLOBAL
  859.         if (proc != curproc) fh += 100;
  860. #endif
  861.           return do_dup(fh, (int)arg);
  862.     }
  863.  
  864.     f = proc->handle[fh];
  865.     if (!f) return EIHNDL;
  866.  
  867.     switch(cmd) {
  868.     case F_GETFD:
  869.         TRACE(("Fcntl F_GETFD"));
  870.         if (fh < 0) return EIHNDL;
  871.         return proc->fdflags[fh];
  872.     case F_SETFD:
  873.         TRACE(("Fcntl F_SETFD"));
  874.         if (fh < 0) return EIHNDL;
  875.         proc->fdflags[fh] = arg;
  876.         return 0;
  877.     case F_GETFL:
  878.         TRACE(("Fcntl F_GETFL"));
  879.         return f->flags & O_USER;
  880.     case F_SETFL:
  881.         TRACE(("Fcntl F_SETFL"));
  882.         arg &= O_USER;        /* make sure only user bits set */
  883. #if 0
  884.     /* COMPATIBILITY WITH OLD VERSIONS ONLY */
  885.     /* THIS CODE WILL GO AWAY. REALLY! */
  886.         if (arg & 4) {
  887.             arg |= O_NDELAY;
  888.             arg &= ~4;
  889.         }
  890. #endif
  891.  
  892.     /* make sure the file access and sharing modes are not changed */
  893.         arg &= ~(O_RWMODE|O_SHMODE);
  894.         arg |= f->flags & (O_RWMODE|O_SHMODE);
  895.         f->flags &= ~O_USER;    /* set user bits to arg */
  896.         f->flags |= arg;
  897.         return 0;
  898.     case FSTAT:
  899.         return (*f->fc.fs->getxattr)(&f->fc, (XATTR *)arg);
  900.     case F_SETLK:
  901.     case F_SETLKW:
  902.     /* make sure that the file was opened with appropriate permissions */
  903.         fl = (struct flock *)arg;
  904.         if (fl->l_type == F_RDLCK) {
  905.             if ( (f->flags & O_RWMODE) == O_WRONLY )
  906.                 return EACCDN;
  907.         } else {
  908.             if ( (f->flags & O_RWMODE) == O_RDONLY )
  909.                 return EACCDN;
  910.         }
  911.         /* fall through to device ioctl */
  912.     default:
  913.         TRACE(("Fcntl mode %x: calling ioctl",cmd));
  914.         r = (*f->dev->ioctl)(f, cmd, (void *)arg);
  915.         if (r == EINVFN && is_terminal(f)) {
  916.             r = tty_ioctl(f, cmd, (void *)arg);
  917.         }
  918.         return r;
  919.     }
  920. }
  921.  
  922. /*
  923.  * fselect(timeout, rfd, wfd, xfd)
  924.  * timeout is an (unsigned) 16 bit integer giving the maximum number
  925.  * of milliseconds to wait; rfd, wfd, and xfd are pointers to 32 bit
  926.  * integers containing bitmasks that describe which file descriptors
  927.  * we're interested in. These masks are changed to represent which
  928.  * file descriptors actually have data waiting (rfd), are ready to
  929.  * output (wfd), or have exceptional conditions (xfd -- currently
  930.  * ignored). If timeout is 0, fselect blocks until some file descriptor
  931.  * is ready; otherwise, it waits only "timeout" milliseconds.
  932.  * Return value: number of file descriptors that are available for
  933.  * reading/writing; or a negative error number.
  934.  */
  935.  
  936. /* helper function for time outs */
  937. static void
  938. unselectme(p)
  939.     PROC *p;
  940. {
  941.     wakeselect((long)p);
  942. }
  943.  
  944. long ARGS_ON_STACK
  945. f_select(timeout, rfdp, wfdp, xfdp)
  946.     unsigned timeout;
  947.     long *rfdp, *wfdp, *xfdp;
  948. {
  949.     long rfd, wfd;
  950.     long mask, bytes;
  951.     int i, count;
  952.     FILEPTR *f;
  953.     PROC *p;
  954.     TIMEOUT *t;
  955.     short sr;
  956.  
  957.     UNUSED(xfdp);
  958.  
  959.     if (rfdp) {
  960.         rfd = *rfdp; *rfdp = 0;
  961.     }
  962.     else
  963.         rfd = 0;
  964.     if (wfdp) {
  965.         wfd = *wfdp; *wfdp = 0;
  966.     }
  967.     else
  968.         wfd = 0;
  969.  
  970.     TRACE(("Fselect(%u, %lx, %lx)", timeout, rfd, wfd));
  971.     p = curproc;            /* help the optimizer out */
  972.  
  973.     /* first, validate the masks */
  974.     mask = 1L;
  975.     for (i = 0; i < MAX_OPEN; i++) {
  976.         if ( ((rfd & mask) || (wfd & mask)) && !(p->handle[i]) ) {
  977.             DEBUG(("Fselect: invalid handle"));
  978.             return EIHNDL;
  979.         }
  980.         mask = mask << 1L;
  981.     }
  982.  
  983. /* now, loop through the file descriptors, setting up the select process */
  984. /* NOTE: wakeselect will set p->wait_cond to 0 if data arrives during the
  985.  * selection
  986.  * Also note: because of the validation above, we may assume that the
  987.  * file handles are valid here. However, this assumption may no longer
  988.  * be true after we've gone to sleep, since a signal handler may have
  989.  * closed one of the handles.
  990.  */
  991.  
  992.     mask = 1L;
  993.     count = 0;
  994.     curproc->wait_cond = (long)wakeselect;        /* flag */
  995.  
  996.     for (i = 0; i < MAX_OPEN; i++) {
  997.         if (rfd & mask) {
  998.             f = p->handle[i];
  999.             if ((*f->dev->select)(f, (long)p, O_RDONLY)) {
  1000.                 count++;
  1001.                 *rfdp |= mask;
  1002.             }
  1003.         }
  1004.         if (wfd & mask) {
  1005.             f = p->handle[i];
  1006.             if ((*f->dev->select)(f, (long)p, O_WRONLY)) {
  1007.                 count++;
  1008.                 *wfdp |= mask;
  1009.             }
  1010.         }
  1011.         mask = mask << 1L;
  1012.     }
  1013.  
  1014.     if (count == 0) {
  1015.         /* OK, now let's set a timeout */
  1016.  
  1017.         if (timeout) {
  1018.             t = addtimeout((long)timeout, unselectme);
  1019.         } else {
  1020.             t = 0;
  1021.         }
  1022.  
  1023.         sr = spl7();
  1024.  
  1025.     /* curproc->wait_cond changes when data arrives or the timeout happens */
  1026.         while (curproc->wait_cond == (long)wakeselect) {
  1027.             TRACE(("sleeping in Fselect"));
  1028.             sleep(SELECT_Q, (long)wakeselect);
  1029.         }
  1030.         spl(sr);
  1031.  
  1032.     /* we can cancel the time out now (if it hasn't already happened) */
  1033.         if (t) canceltimeout(t);
  1034.  
  1035.     /* OK, let's see what data arrived (if any) */
  1036.         mask = 1L;
  1037.         for (i = 0; i < MAX_OPEN; i++) {
  1038.             if (rfd & mask) {
  1039.                 f = p->handle[i];
  1040.                 if (f) {
  1041.                     bytes = 1L;
  1042.                     (void)(*f->dev->ioctl)(f, FIONREAD,&bytes);
  1043.                     if (bytes > 0) {
  1044.                     *rfdp |= mask;
  1045.                     count++;
  1046.                     }
  1047.                 }
  1048.             }
  1049.             if (wfd & mask) {
  1050.                 f = p->handle[i];
  1051.                 if (f) {
  1052.                     bytes = 1L;
  1053.                     (void)(*f->dev->ioctl)(f, FIONWRITE,&bytes);
  1054.                     if (bytes > 0) {
  1055.                     *wfdp |= mask;
  1056.                     count++;
  1057.                     }
  1058.                 }
  1059.             }
  1060.             mask = mask << 1L;
  1061.         }
  1062.     }
  1063.  
  1064.     /* at this point, we either have data or a time out */
  1065.     /* cancel all the selects */
  1066.     mask = 1L;
  1067.  
  1068.     for (i = 0; i < MAX_OPEN; i++) {
  1069.         if (rfd & mask) {
  1070.             f = p->handle[i];
  1071.             if (f)
  1072.                 (*f->dev->unselect)(f, (long)p, O_RDONLY);
  1073.         }
  1074.         if (wfd & mask) {
  1075.             f = p->handle[i];
  1076.             if (f)
  1077.                 (*f->dev->unselect)(f, (long)p, O_WRONLY);
  1078.         }
  1079.         mask = mask << 1L;
  1080.     }
  1081.  
  1082.     TRACE(("Fselect: returning %d", count));
  1083.     return count;
  1084. }
  1085.  
  1086.  
  1087. /*
  1088.  * GEMDOS extension: Fmidipipe
  1089.  * Fmidipipe(pid, in, out) manipultes the MIDI file handles (handles -4 and -5)
  1090.  * of process "pid" so that they now point to the files with handles "in" and
  1091.  * "out" in the calling process
  1092.  */
  1093.  
  1094. long ARGS_ON_STACK
  1095. f_midipipe(pid, in, out)
  1096.     int pid, in, out;
  1097. {
  1098.     PROC *p;
  1099.     FILEPTR *fin, *fout;
  1100.  
  1101. /* first, find the process */
  1102.  
  1103.     if (pid == 0)
  1104.         p = curproc;
  1105.     else {
  1106.         p = pid2proc(pid);
  1107.         if (!p)
  1108.             return EFILNF;
  1109.     }
  1110.  
  1111. /* next, validate the input and output file handles */
  1112.     if (in < MIN_HANDLE || in >= MAX_OPEN || (0==(fin = curproc->handle[in])))
  1113.         return EIHNDL;
  1114.     if ( (fin->flags & O_RWMODE) == O_WRONLY ) {
  1115.         DEBUG(("Fmidipipe: input side is write only"));
  1116.         return EACCDN;
  1117.     }
  1118.     if (out < MIN_HANDLE || out >= MAX_OPEN || (0==(fout = curproc->handle[out])))
  1119.         return EIHNDL;
  1120.     if ( (fout->flags & O_RWMODE) == O_RDONLY ) {
  1121.         DEBUG(("Fmidipipe: output side is read only"));
  1122.         return EACCDN;
  1123.     }
  1124.  
  1125. /* OK, duplicate the handles and put them in the new process */
  1126.     fin->links++; fout->links++;
  1127.     (void)do_pclose(p, p->midiin);
  1128.     (void)do_pclose(p, p->midiout);
  1129.     p->midiin = fin; p->midiout = fout;
  1130.     return 0;
  1131. }
  1132.